<?php
class RSA
{
    const  RSA_ENCRYPT_BLOCK_SIZE = 117;// RSA加密区块大小
    const  RSA_DECRYPT_BLOCK_SIZE = 128;// RSA解密区块大小

    /**
     * @desc 使用私钥生成签名字符串
     * @param mixed $assocArr 加密内容
     * @param string $rsaPriKeyStr 私钥原始字符串，默认不含PEM格式前后缀
     * @param bool $isNotSuffix 是否不带PEM格式前后缀
     * @return string 签名结果字符串
     * @throws \Exception
     */
    public static function sign($assocArr, $rsaPriKeyStr,$isNotSuffix=true)
    {
        if (empty($rsaPriKeyStr) || empty($assocArr)) return false;
        if (!function_exists('openssl_pkey_get_private') || !function_exists('openssl_sign')) throw new \Exception("openssl扩展不存在");
        if ($isNotSuffix) $rsaPriKeyPem = self::convertRSAKeyStr2Pem($rsaPriKeyStr, 1);
        else $rsaPriKeyPem = $rsaPriKeyStr;
        $priKey = openssl_pkey_get_private($rsaPriKeyPem);
        if (is_array($assocArr)){
            ksort($assocArr);
            $parts = array();
            foreach ($assocArr as $k => $v) $parts[] = $k . '=' . $v;
            $assocArr = implode('&', $parts);
        }
        if (!is_string($assocArr))return false;
        openssl_sign($assocArr, $sign, $priKey);
        openssl_free_key($priKey);
        return base64_encode($sign);
    }

    /**
     * @desc 使用公钥校验签名
     * @param mixed $assocArr 入参数据，签名属性名固定为rsaSign
     * @param string $sign 签名
     * @param string $rsaPubKeyStr 公钥原始字符串，默认不含PEM格式前后缀
     * @param bool $isNotSuffix 是否不带PEM格式前后缀
     * @return bool true 验签通过|false 验签不通过
     * @throws \Exception
     */
    public static function checkSign($assocArr,$sign, $rsaPubKeyStr,$isNotSuffix=true)
    {
        if (empty($assocArr) || empty($assocArr) || empty($rsaPubKeyStr) || empty($sign)) return false;
        if (!function_exists('openssl_pkey_get_public') || !function_exists('openssl_verify')) throw new \Exception("openssl扩展不存在");
        if (is_array($assocArr)){
            ksort($assocArr); // 倒序
            $parts = array();
            foreach ($assocArr as $k => $v) $parts[] = $k . '=' . $v;
            $assocArr = implode('&', $parts);
        }
        if (!is_string($assocArr))return false;
        $sign = base64_decode($sign);
        if ($isNotSuffix) $rsaPubKeyPem = self::convertRSAKeyStr2Pem($rsaPubKeyStr);
        else $rsaPubKeyPem = $rsaPubKeyStr;
        $pubKey = openssl_pkey_get_public($rsaPubKeyPem);
        $result = (bool)openssl_verify($assocArr, $sign, $pubKey);
        openssl_free_key($pubKey);
        return $result;
    }

    /**
     * @desc 将密钥由字符串（不换行）转为PEM格式
     * @param string $rsaKeyStr 原始密钥字符串
     * @param int $keyType 0 公钥|1 私钥，默认0
     * @return string PEM格式密钥
     * @throws \Exception
     */
    public static function convertRSAKeyStr2Pem($rsaKeyStr, $keyType = 0)
    {
        $pemWidth = 64;
        $rsaKeyPem = '';
        $begin = '-----BEGIN ';
        $end = '-----END ';
        $key = ' KEY-----';
        $type = $keyType ? 'PRIVATE' : 'PUBLIC';
        $keyPrefix = $begin . $type . $key;
        $keySuffix = $end . $type . $key;
        $rsaKeyPem .= $keyPrefix . "\n";
        $rsaKeyPem .= wordwrap($rsaKeyStr, $pemWidth, "\n", true) . "\n";
        $rsaKeyPem .= $keySuffix;
        if (!function_exists('openssl_pkey_get_public') || !function_exists('openssl_pkey_get_private')) return false;
        if ($keyType == 0 && false == openssl_pkey_get_public($rsaKeyPem)) return false;
        if ($keyType == 1 && false == openssl_pkey_get_private($rsaKeyPem)) return false;
        return $rsaKeyPem;
    }

    /**
     * RSA数据加密解密 私钥-加解密
     * @param string $dataStr
     * @param string $type encode加密  decode解密  $rsaKey RSA密钥
     * @param string $rsaKey
     * @return string 加密或解密后的字符
     * @throws Exception
     * @Description: 字符过长的话需要分段加密/解密
     */
    public static function RASPrivateEncrypt($dataStr,$type,$rsaKey){
        if (empty($dataStr)) {
            return 'data参数不能为空';
        }

        $rsaKey = self::convertRSAKeyStr2Pem($rsaKey,1); // 获取公钥证书
        if ($type=='decode') {
            //私钥解密
            $data=base64_decode($dataStr);
            $result = '';
            $data = str_split($data, self::RSA_DECRYPT_BLOCK_SIZE);
            foreach ($data as $block) {
                openssl_private_decrypt($block, $decrypted, $rsaKey);
                $result .= $decrypted;
            }
        }else{
            //私钥加密
            $result = '';
            $data = str_split($dataStr, self::RSA_ENCRYPT_BLOCK_SIZE);
            foreach ($data as $block) {
                openssl_private_encrypt($block, $crypted, $rsaKey);
                $result .= $crypted;
            }
            $result=base64_encode($result);
        }
        return $result;
    }
    /**
     * RSA数据加密解密 公钥-加解密
     * @param string $dataStr
     * @param string $type encode加密  decode解密  $rsaKey RSA密钥
     * @param string $rsaKey
     * @return string 加密或解密后的字符
     * @throws Exception
     * @Description: 字符过长的话需要分段加密/解密
     */
    public static function RASPublicEncrypt($dataStr,$type,$rsaKey){
        if (empty($dataStr)) {
            return 'data参数不能为空';
        }

        $rsaKey = self::convertRSAKeyStr2Pem($rsaKey); // 获取公钥证书
        if ($type=='decode') {
            //私钥解密
            $data=base64_decode($dataStr);
            $result = '';
            $data = str_split($data, self::RSA_DECRYPT_BLOCK_SIZE);
            foreach ($data as $block) {
                openssl_public_decrypt($block, $decrypted, $rsaKey);
                $result .= $decrypted;
            }
        }else{
            //私钥加密
            $result = '';
            $data = str_split($dataStr, self::RSA_ENCRYPT_BLOCK_SIZE);
            foreach ($data as $block) {
                openssl_public_encrypt($block, $crypted, $rsaKey);
                $result .= $crypted;
            }
            $result=base64_encode($result);
        }
        return $result;
    }
}
const PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCb20u1DXHv9O0oR4sm/taKARwB9R8Fauw581NjQH0eQTFzRtoydgIPLu/WOEGRaY/2x6+RJ3f/DG84ozdY4n/A4czMlHH9/iE2GYhw0boQpw93n/HVZxEHqsiq5SrH33Ez6fryYGUYjqmxmWc7lHz6VmyFQdGcZ78GF0Nhi2detQIDAQAB";
const PRIVATE_KEY = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJvbS7UNce/07ShHiyb+1ooBHAH1HwVq7DnzU2NAfR5BMXNG2jJ2Ag8u79Y4QZFpj/bHr5End/8MbzijN1jif8DhzMyUcf3+ITYZiHDRuhCnD3ef8dVnEQeqyKrlKsffcTPp+vJgZRiOqbGZZzuUfPpWbIVB0ZxnvwYXQ2GLZ161AgMBAAECgYArXi4GxyL5HjIPjzjNNQQFiqF8efST0VjCF08QwxUNoh5ccU6t0+Bm0SyzcxvrlnAUvyO/RDhDo/Ye0GvKM9xQJAXJgO+3RZ//xEwspz56Sjc+ONiQIrurwLTtlEBmTucGLSnT9GVOvXmB5NTFGTwm7qb+R0W1bW86O0KJ2B4egQJBANfJz9pTluDHf/XTlggep5xIFVZpf3v2O2sjRioqyN3d3e9fELniif8cZQxbMH+9cofabm4D5DLNBWg7+PXsJ00CQQC45nCzQEKKWl2jgsDMCKlwgYYcg+LCVy7nTvFDl3XHYfZni4Z7wpVCkCvzGF6qCmEwz5AyluecmA0Am6LVRXEJAkBPqjbtUHzcQWrRU6sJFmAkx0vxWgNxvWcUV7J4sND1cAqWa89eAO+XWmFH3YabMlLNKuwn+5HM23oKkFGKYQPlAkAgMad/3nl3g4J4XOTa4cs21qaWQnRyKCH3jmw9u5p7S9hOcSHKXLgGbfnpCt44tzPy/sD5vgK35lWlPHQetEeZAkAxjMoK0XNplKP+kVxYXSWnH6Jf02Mgkqu36iDSsggs5/lmEvJ+xgSPGMcqs7jyA2XlZvEG6kp7M716oqd08+e1";

$encryptContent = "coDdNwo0sAkRWwwwYdcyRQ==";

// 使用公钥对AES进行RSA加密
print_r($content=RSA::RASPublicEncrypt($encryptContent,"encode",PUBLIC_KEY));
echo "\n";
// 使用私钥对AES进行RSA解密
print_r(RSA::RASPrivateEncrypt($content,"decode",PRIVATE_KEY));
echo "\n";

// 使用私钥对AES进行RSA加密
print_r($content=RSA::RASPrivateEncrypt($encryptContent,"encode",PRIVATE_KEY));
echo "\n";
// 使用公钥对AES进行RSA解密
print_r(RSA::RASPublicEncrypt($content,"decode",PUBLIC_KEY));

